package manage.run;

import m.appserver.RequestUtil;
import m.appserver.ResponseUtil;
import m.common.action.Action;
import m.system.RuntimeData;
import m.system.db.DBManager;
import m.system.db.DBOper;
import m.system.db.DBResult;
import m.system.util.ArrayUtil;
import m.system.util.GenerateID;
import m.system.util.StringUtil;
import manage.model.ServerDetailSql;
import manage.model.ServerRequest;
import manage.model.ServerRequestDetail;
import manage.model.ServerSetting;
import manage.service.ServerSettingService;

import java.util.*;

public class ServerFilter {
	private static final ThreadLocal<ServerFilter> ins = new ThreadLocal<>();
	private ServerFilter(){}
	public static ServerFilter threadInstance(){
		if(null==ins.get()){
			ins.set(new ServerFilter());
		}
		return ins.get();
	}
	public static void clearInstance(){
		ins.remove();
	}

	private RequestUtil request;
	private ResponseUtil response;
	private ServerSetting setting;
	private long timeLong;
	private String oid;
	private String path;

	private static boolean isBoolean=true;
	private static final Map<String,ServerRequest> requestMap0= new HashMap<>();
	private static final Map<String,ServerRequest> requestMap1= new HashMap<>();
	private static final Map<String,List<ServerRequestDetail>> detailMap0= new HashMap<>();
	private static final Map<String,List<ServerRequestDetail>> detailMap1= new HashMap<>();
	private static final List<ServerDetailSql> sqlList0= new ArrayList<>();
	private static final List<ServerDetailSql> sqlList1= new ArrayList<>();
	public static Map<String,ServerRequest> getRequestMap(){
		return getBoolean()?requestMap0:requestMap1;
	}
	public static Map<String,List<ServerRequestDetail>> getDetailMap(){
		return getBoolean()?detailMap0:detailMap1;
	}
	public static List<ServerDetailSql> getSqlList(){
		return getBoolean()?sqlList0:sqlList1;
	}
	private static boolean getBoolean() {
		return isBoolean;
	}
	public static void reset(){
		isBoolean=!isBoolean;
	}
	public ServerRequest getRequestModel(String path) {
		ServerRequest sr=getRequestMap().get(path);
		if(null==sr) {
			sr=new ServerRequest();
			getRequestMap().put(path,sr);
			sr.setContextPath(path);
			if(path.indexOf("/action")==0) {
				sr.setType("action");
			}else if(path.indexOf("/page")==0) {
				sr.setType("page");
			}else {
				sr.setType("other");
			}
			if(path.indexOf(".")>0) {
				String suffix=path.substring(path.lastIndexOf(".")+1);
				if(suffix.length()<=10) {
					sr.setSuffix(suffix);
				}
			}
			sr.setTotal(0);
			sr.setAccessLong(0.0);
			sr.setAvgLong(0.0);
		}
		return sr;
	}
	public List<ServerRequestDetail> getRequestDetail(String path){
        return getDetailMap().computeIfAbsent(path, k -> new ArrayList<>());
	}
	
	public void filterBefore(RequestUtil req, ResponseUtil res) throws Exception {
		setting=RuntimeData.getService(ServerSettingService.class).getUniqueModel();
		if(!setting.getRequestMonitor().equals("Y")) return ;
		this.request=req;
		this.response=res;
		this.timeLong=System.currentTimeMillis();
		this.oid=GenerateID.generatePrimaryKey();
		this.path=request.getUri();
	}
	public void addSqlAndParam(Long timeLong, DBOper method, DBResult result, String[] sql, Object[] params){
		if(null==setting) return;
		if(!setting.getRequestMonitor().equals("Y")) return ;
		if(timeLong/1000>setting.getSlowSqlSecond() || setting.getSaveErrorSql().equals("Y")&&result==DBResult.Error){
			ServerDetailSql ds=new ServerDetailSql();
			ds.setOid(GenerateID.generatePrimaryKey());
			ds.setServerDetail(new ServerRequestDetail());
			ds.getServerDetail().setOid(oid);
			ds.setExeLong(timeLong);
			ds.setExeMethod(method.name());
			ds.setExeResult(result.name());
			ds.setExeSql(ArrayUtil.connection(sql,"; \r\n")+"; ");
			ds.setExeParam(DBManager.outParams(params));
			getSqlList().add(ds);
		}
	}

	public void filterAfter() throws Exception {
		if(!setting.getRequestMonitor().equals("Y")) return ;
		long tl=System.currentTimeMillis()-this.timeLong;
		ServerRequest sr=getRequestModel(path);
		List<ServerRequestDetail> list=getRequestDetail(path);
		ServerRequestDetail detail=new ServerRequestDetail();
		detail.setOid(this.oid);
		detail.setServerRequest(sr);
		detail.setLogIp(StringUtil.noSpace(Action.getIpAddress(request),20));
		detail.setLogDate(new Date());
		detail.setAccessLong(new Long(tl).intValue());
		detail.setUserAgent(request.getHeader("User-Agent"));
		list.add(detail);
	}

}
